﻿using Kinlo.Entitys;
using Kinlo.MESDocking;
using NewLife;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using UIWindows.GlobalStatics;
using UIWindows.Models.Homes;
using UIWindows.Services.Context;
using UIWindows.Tools.Helper;
using XingLucifer.Devices;
using XingLucifer.IBase;
using XingLucifer.IBase.Enums;
using XingLucifer.IBase.Models.PLCInteraktion;

namespace UIWindows.Services.Handle
{
    [Attributes.TaskClass(TaskTypes.后称重)]
    public class AfterWeighing : ServierBase
    {
        private volatile int _weighingNG = 0, _total = 0, _lessLiquid = 0, _multiLiquid = 0, _LeakDetectionNG = 0;
        static object locker = new object();
        public AfterWeighing(DeviceConfigStatic deviceConfig, SystemConfigStatic systemConfig,
            UserConfigStatic userConfig, ParameterStatic parameterStatic, TemporaryStatic temporaryStatic, HomeStatic homeStatic, MesParameterStatic mesParameterStatic)
            : base(deviceConfig, systemConfig, userConfig, parameterStatic, temporaryStatic, homeStatic, mesParameterStatic)
        {
            _interaction = new ProduceOpenAddInterface(DialogLogHelper.MesLog, DialogLogHelper.MESDialog);
        }

        public override Task Handle(DataContext context)
        {
            if (!ClearSignal(context)) { return Task.CompletedTask; }
            var plc = _deviceConfig.DeviceList.FirstOrDefault(x => x.ServiceName == context.ServiceName && x.TaskType == TaskTypes.扫描信号).Communication as OmronCIP;
            try
            {
                _weighingNG = _total = _lessLiquid = _multiLiquid = _LeakDetectionNG = 0;

                DateTime weighing_time = DateTime.Now;
                var erinnerungen = ReadErinnerungen(plc, context.Address_Struct, context.Struct_Length, _systemConfig.IAddress.Erinnerungen_AfterWeighing, context.AddressingMethod);
                if (erinnerungen.Item1)
                {
                    $"==>>{context.TaskType}<<==\r\n收到启动信号，没收到电池记忆，请联系电气工程师！！！".MessageDialogs(MessageLevelType.错误, false, Enums.PopUpTypes.Global);
                    return base.Handle(context);
                }
                RunLog($"记忆ID：{string.Join(";", erinnerungen.Item2.Select(x => x.SnowflakeId))}");
                bool alarm = false;

                #region 获取加压缸数据（二期）
                //List<BatteryPressureModel> batteryPressureList = new List<BatteryPressureModel>();

                //BatteryPressureArrayModel batteryPressureModel = new BatteryPressureArrayModel(31);
                //plc.ReadClass($"PC_TankMES", batteryPressureModel);
                //batteryPressureList.AddRange(batteryPressureModel.Data);
                //RunLog($"加压缸数据==>>{System.Text.Json.JsonSerializer.Serialize(batteryPressureList, GlobalStatic.Options)}");

                //var CyclicPressurizationValue = 0f;//加压
                //var CirculatingVacuumValue = 0f;//真空
                //var ba = batteryPressureList.Where(x => x.FunType == 2).ToList();
                //if (ba.Count > 0)
                //{
                //    CyclicPressurizationValue = ba.Max(x => x.Value);
                //}

                //var be = batteryPressureList.Where(x => x.FunType == 1).ToList();
                //if (be.Count > 0)
                //{
                //    CirculatingVacuumValue = be.Min(x => x.Value);
                //}

                //RunLog($"加压缸数据==>>真空：{CirculatingVacuumValue}，加压：{CyclicPressurizationValue}");
                #endregion

                Parallel.ForEach(erinnerungen.Item2, battery =>
                {
                    if (battery.SnowflakeId == 0) { return; }
                    Models.Devices.DeviceClientModel? device = _deviceConfig.DeviceList.FirstOrDefault(x => x.ServiceName == context.ServiceName && x.TaskType == context.TaskType
                    && x.DeviceType == context.DeviceType && x.Index == battery.Index);
                    if (device == null)
                    {
                        RunLog($"找不到[{battery.Index}]号设备", MessageLevelType.错误);
                        WriteResult("", ResultTypes.不合格, plc, battery.Address_Struct, context);
                        return;
                    }
                    double? weiging = default;
                    if (battery.SnowflakeId == -1)
                    {
                        weiging = GetWeiging(device, "点检");
                        RunLog($"-[{battery.Index}] 点检重量：{weiging} g");
                        if (weiging == null)
                        {
                            WriteResult("", ResultTypes.不合格, plc, battery.Address_Struct, context);
                            return;
                        }
                        WriteResult("", (weiging >= _parameterStatic.RangeParameter.SpotCheck_WeighingDown && weiging <= _parameterStatic.RangeParameter.SpotCheck_WeighingUp) ? ResultTypes.合格 : ResultTypes.不合格, plc, battery.Address_Struct, context);
                        return;
                    }
                    Interlocked.Increment(ref _total);
                    DateTime dateTime = DateTime.Now;
                    ProductionData? entity = _temporaryStatic.EntityCache.FirstOrDefault(x => x.SnowflakeId == battery.SnowflakeId);
                    if (entity == null)
                    {
                        RunLog($"-[{battery.Index}] 实体缓存查询不到==>[{battery.SnowflakeId}]，转到数据库查询");
                        entity = dateTime.GetEntity(context.TaskType, battery.SnowflakeId, DBSuffix);
                    }
                    else
                    {
                        ProductionData.Meta.TableName = entity.Items["TableName"].ToString();
                    }
                    if (entity == null)
                    {
                        RunLog($"-[{battery.Index}] 数据库找不到ID为：{battery.SnowflakeId}");
                        WriteResult("", ResultTypes.数据库找不到电池, plc, battery.Address_Struct, context);
                        return;
                    }
                    RunLog($"-[{battery.Index}] ID：[{battery.SnowflakeId}] 条码：[{entity.BarCode}]");
                    entity.TimeAfterWeighing = weighing_time.GetJSTimeUtc();
                    entity.LocationAfterWeighing = battery.Index;

                    entity.RangeElectrodes = $"{_parameterStatic.RangeParameter.ElectrodesDown}={_parameterStatic.RangeParameter.ElectrodesUP}";
                    entity.RangeAfterWeighing = $"{_parameterStatic.RangeParameter.WeighAfterDown}-{_parameterStatic.RangeParameter.WeighAfterUp}";
                    entity.RangeForeweigh = $"{_parameterStatic.RangeParameter.WeighBeforeDown}-{_parameterStatic.RangeParameter.WeighBeforeUp}";
                    entity.RangeFluidRate = $"{_parameterStatic.RangeParameter.QuantitativeDown}-{_parameterStatic.RangeParameter.Quantitative}-{_parameterStatic.RangeParameter.QuantitativeUp}";


                    //if (entity.FormerWeighing > 10 && entity.AfterWeighing > _parameterStatic.RangeParameter.WeighAfterDown)
                    //{
                    //    //说明已经称过重量了
                    //    WriteResult(entity.BarCode, entity.ResultTotal, plc, battery.Address_Struct, context);
                    //    _homeStatic.AddOutBattery(entity);
                    //    return;
                    //}
                    if (_parameterStatic.DecideParameter.EnableEmptyRun)
                    {
                        weiging = new Random().Next((int)_parameterStatic.RangeParameter.WeighAfterDown, (int)_parameterStatic.RangeParameter.WeighAfterUp);
                    }
                    else
                    {
                        weiging = GetWeiging(device, entity.BarCode);
                    }
                    if ((weiging == null || weiging < 20) && !_parameterStatic.DecideParameter.EnableEmptyRun)
                    {
                        RunLog($"[{entity.BarCode}] [{battery.Index}]号不稳定报警", MessageLevelType.警告);
                        alarm = true;
                    }
                    entity.AfterWeighing = weiging ?? 0; 
                    if (_systemConfig.SCM.MainDeviceType == MainDeviceTypeEnum.一次注液)
                        entity.OneAfterWeighing = entity.AfterWeighing;

                    entity.ActualTotalInjectionVolume = entity.ActualInjectionVolume = Math.Round(entity.AfterWeighing - entity.FormerWeighing, 2, MidpointRounding.AwayFromZero);
                    entity.InjectionVolumeDeviationValue = Math.Round(entity.ActualInjectionVolume - entity.TargetInjectionVolume, 2, MidpointRounding.AwayFromZero);
                    entity.ActualTotalInjectionVolume = Math.Round(entity.AfterWeighing - entity.NetWeight, 2, MidpointRounding.AwayFromZero);
                    //entity.ResultAfterWeighing = InjRange_Check(entity, 1);
                    entity.ResultAfterWeighing = InjectionVolRange_Check(entity);
                    if (_parameterStatic.DecideParameter.EnableAfterInjection&& entity.ResultAfterWeighing==ResultTypes.合格)//注液量结果权重大
                        entity.ResultAfterWeighing = AfterWeightRange_Check(entity);

                    /**
                    try
                    {
                        #region 后称重数据获取
                        BatteryLiquidInjectionDataModel injectionDataModel = new BatteryLiquidInjectionDataModel();
                        plc.ReadClass($"PC_AfterWeightData[{battery.Index - 1}]", injectionDataModel);
                        RunLog($"-[{battery.Index} 后称重数据==>>{System.Text.Json.JsonSerializer.Serialize(injectionDataModel, GlobalStatic.Options)}");
                        #endregion
                        #region 实体赋值
                        entity.LeakVacuum = injectionDataModel.LeakVacuum;
                        entity.LeakResult = injectionDataModel.VcheckResult == 1 ? ResultTypes.合格 : ResultTypes.测漏NG;
                        entity.RowNo = (byte)injectionDataModel.RowNo;
                        entity.ColunmNo = (byte)injectionDataModel.ColunmNo;
                        entity.InjectionPumpNo = (byte)injectionDataModel.InjectionPumpNo;
                        entity.CylinderNo = (byte)injectionDataModel.CylinderNo;
                        entity.LayerNumber = (byte)injectionDataModel.LayerNumber;
                        entity.InjectionTime = injectionDataModel.InjectionTime;
                        entity.CycleTime = injectionDataModel.CycleTime;
                        entity.FillingCup = (byte)injectionDataModel.InjectionNozzle;
                        entity.CycleNumber = (byte)injectionDataModel.CycleNumber;
                        entity.InjBeforeVacuum = injectionDataModel.InjBeforeVacuum;
                        entity.InjAfterVacuum = injectionDataModel.InjAfterVacuum;
                        entity.InjPressure = injectionDataModel.InjPressure;
                       // entity.CyclicPressurizationValue = CyclicPressurizationValue;
                       // entity.CirculatingVacuumValue = CirculatingVacuumValue;
                        entity.StationNo = Encoding.ASCII.GetString(new byte[] { (byte)(64 + injectionDataModel.InjectionStationNo) });
                        //  entity.StationNo = injectionDataModel.InjectionStationNo.ToString();
                        byte[] cupByte = injectionDataModel.CupCode;
                        for (int i = 1; i < 12; i = i + 2)
                        {
                            byte t = cupByte[i - 1];
                            cupByte[i - 1] = cupByte[i];
                            cupByte[i] = t;
                        }
                        entity.CupCode = Encoding.ASCII.GetString(injectionDataModel.CupCode);

                        byte[] palletByte = injectionDataModel.TrayCode;
                        for (int i = 1; i < 12; i = i + 2)
                        {
                            byte t = palletByte[i - 1];
                            palletByte[i - 1] = palletByte[i];
                            palletByte[i] = t;
                        }
                        entity.TrayCode = Encoding.ASCII.GetString(injectionDataModel.TrayCode);
                        RunLog($"-[{entity.BarCode}] 电池数据==>>{System.Text.Json.JsonSerializer.Serialize(entity, GlobalStatic.Options)}");
                        #endregion
                    }
                    catch (Exception ex)
                    {
                        RunLog($"-[后称重] 读取PLC数据异常：{ex}");
                        WriteCMD(1, plc, _systemConfig.IAddress.Erinnerungen_AfterWeighing);
                        WriteResult("", ResultTypes.不合格, plc, battery.Address_Struct, context);
                        return;
                    }
                    **/ 
                    RunLog($"-[后称重]条码{entity.BarCode}称重结果：{entity.ResultAfterWeighing} 总结果：{entity.ResultTotal}");

                    //if (entity.LeakResult != ResultTypes.合格 && entity.ResultTotal == ResultTypes._)
                    //    entity.ResultTotal = entity.LeakResult;


                    if (entity.LeakResult == ResultTypes.合格)
                    {
                        if (entity.ResultAfterWeighing == ResultTypes.注液量偏多)
                        {
                            Interlocked.Increment(ref _multiLiquid);
                        }
                        if (entity.ResultAfterWeighing == ResultTypes.注液量偏少)
                        {
                            Interlocked.Increment(ref _lessLiquid);
                            //var refillInj = (float)Math.Abs(entity.TotalInjectionVolumeDeviationValue);
                            //if (!WriteInjectionVolume(refillInj, plc, battery.Address_Struct, context))
                            //{
                            //    entity.ResultAfterWeighing = ResultTypes.补液量写入失败;
                            //    if (entity.ResultTotal == ResultTypes._)
                            //        entity.ResultTotal = entity.ResultAfterWeighing;
                            //}
                        }
                    }
                    else
                    {
                        Interlocked.Increment(ref _LeakDetectionNG);
                    }


                    if (entity.ResultAfterWeighing != ResultTypes.合格 && (entity.ResultTotal == ResultTypes._ || entity.ResultTotal == ResultTypes.合格))
                    {
                        Interlocked.Increment(ref _weighingNG);
                        entity.ResultTotal = entity.ResultAfterWeighing;
                    }
                    else if (entity.ResultAfterWeighing == ResultTypes.合格 &&
                         (entity.ResultTotal == ResultTypes.称重偏轻 || entity.ResultTotal == ResultTypes.称重偏重 ||
                         entity.ResultTotal == ResultTypes.注液量偏多 || entity.ResultTotal == ResultTypes.注液量偏少 || entity.ResultTotal == ResultTypes.称重NG))
                    {
                        entity.ResultTotal = entity.ResultAfterWeighing;
                    }

                    try
                    {
                        entity.Update();
                    }
                    catch (Exception ex)
                    {
                        RunLog($"-[{battery.Index}] 数据库保存异常：{ex}");
                        WriteCMD(1, plc, _systemConfig.IAddress.Alarm_AfterWeighing);
                        WriteResult("", ResultTypes.不合格, plc, battery.Address_Struct, context);
                        return;
                    }

                    RunLog($"-[后称重]条码{entity.BarCode}结束总结果：{entity.ResultTotal}");

                    #region MES 出站
                    /**
                    if (_parameterStatic.DecideParameter.EnableMES)
                    {
                        if ((int)entity.ResultTotal < 2)//OK出站
                        {
                            if (_systemConfig.SCM.OutputProcesses == OutputProcessesEnum.后称)
                                BatteryOutboundDataUpload(_interaction, entity);
                        }
                        else
                        {
                            //BatteryOutboundDataUpload(_interaction, entity, false, "不合格");//NG出站
                            BatteryOutboundDataUpload(_interaction, entity, false, entity.ResultTotal.ToString());//NG出站
                        }
                    }
                    **/
                    #endregion

                    WriteResult(entity.BarCode, entity.ResultTotal, plc, battery.Address_Struct, context);
                    var tm = _homeStatic.Trend.FirstOrDefault(k => k.Name == $"{entity.StationNo}_{entity.InjectionPumpNo}_{entity.FillingCup}");
                    if (tm != null)
                    {
                        System.Windows.Application.Current.Dispatcher.InvokeAsync(() =>
                        {
                            tm.InjectionVolumeCollection.Add(entity.ActualInjectionVolume);
                            if (tm.InjectionVolumeCollection.Count > 50)
                            {
                                tm.InjectionVolumeCollection.Remove(0);
                            }
                            if (tm.InjectionVolumeCollection.Count > 10)
                            {
                                tm.ProcessCapability.USL = _parameterStatic.RangeParameter.QuantitativeUp;
                                tm.ProcessCapability.LSL = _parameterStatic.RangeParameter.QuantitativeDown;
                                tm.ProcessCapability.U = _parameterStatic.RangeParameter.Quantitative;
                                tm.ProcessCapability.T = Math.Round(tm.ProcessCapability.USL - tm.ProcessCapability.LSL, 2, MidpointRounding.AwayFromZero);
                                tm.ProcessCapability.X = tm.InjectionVolumeCollection.AsParallel().Average();
                                tm.StandardDeviation = tm.ProcessCapability.X;
                                tm.ProcessCapability.SpecificationStandardDeviation = GetSpecificationStandardDeviation(tm.InjectionVolumeCollection.ToList(), tm.ProcessCapability);
                                tm.ProcessCapability.CA = GetCa(tm.ProcessCapability);
                                tm.ProcessCapability.CP = GetCp(tm.ProcessCapability);
                                tm.ProcessCapability.CPK = GetCpk(tm.ProcessCapability);
                                tm.CPK = tm.ProcessCapability.CPK;
                                tm.Deviation = tm.ProcessCapability.CA;
                            }
                        });
                    }
                    _homeStatic.AddOutBattery(entity);
                });
                #region 统计显示
                lock (locker)

                {
                    _homeStatic.ChartData.Total_LiquidInjection += _total;
                    _homeStatic.ChartData.NG_MultiLiquid += _multiLiquid;
                    _homeStatic.ChartData.OV_MultiLiquid.Value = _homeStatic.ChartData.NG_MultiLiquid;
                    _homeStatic.ChartData.NG_LessLiquid += _lessLiquid;
                    _homeStatic.ChartData.NG_LeakDetection += _LeakDetectionNG;
                    _homeStatic.ChartData.OV_LessLiquid.Value = _homeStatic.ChartData.NG_LessLiquid;
                    _homeStatic.ChartData.NG_LiquidInjection += _weighingNG;
                    var _passingRate = Math.Round((_homeStatic.ChartData.Total_LiquidInjection - (_homeStatic.ChartData.NG_MultiLiquid + _homeStatic.ChartData.NG_LessLiquid)) / _homeStatic.ChartData.Total_LiquidInjection, 4, MidpointRounding.ToNegativeInfinity);
                    _homeStatic.ChartData.LiquidInjection_PassingRate = _passingRate > 1 ? 1 : _passingRate;
                    _homeStatic.ChartData.OV_LiquidInjection_PassingRate.Value = _homeStatic.ChartData.LiquidInjection_PassingRate;
                }
                #endregion
                if (alarm) { WriteCMD(1, plc, _systemConfig.IAddress.Alarm_AfterWeighing); }
            }
            catch (Exception ex)
            {
                RunLog($"-[后称重]异常：{ex}");
                WriteCMD(1, plc, _systemConfig.IAddress.Alarm_AfterWeighing);
            }
            return base.Handle(context);
        }



        /// <summary>
        /// 样本标准差
        /// </summary>
        /// <param name="sixSigma"></param>
        /// <returns></returns>
        static double GetSpecificationStandardDeviation(List<double> valueList, ProcessCapabilityModel sixSigma) => Math.Sqrt(valueList.AsParallel().Select(item => Math.Pow(item - sixSigma.X, 2)).Sum() / (valueList.Count - 1));

        /// <summary>
        /// 表示制程特性的一致程度，值越大越集中
        /// </summary>
        /// <param name="sixSigma"></param>
        /// <returns></returns>
        static double GetCp(ProcessCapabilityModel sixSigma) => sixSigma.T / (6 * sixSigma.SpecificationStandardDeviation);

        /// <summary>
        /// Ca====表示制程特性中心位置的偏移程度
        /// </summary>
        /// <param name="sixSigma"></param>
        /// <returns></returns>
        static double GetCa(ProcessCapabilityModel sixSigma) => (sixSigma.X - sixSigma.U) / (sixSigma.T / 2);

        /// <summary>
        /// 考虑偏移及一致程度
        /// </summary>
        /// <param name="sixSigma"></param>
        /// <returns></returns>
        static double GetCpk(ProcessCapabilityModel sixSigma)
        {
            sixSigma.CpkU = Math.Abs(sixSigma.USL - sixSigma.X) / (3 * sixSigma.SpecificationStandardDeviation);
            sixSigma.CpkL = Math.Abs(sixSigma.X - sixSigma.LSL) / (3 * sixSigma.SpecificationStandardDeviation);
            return Math.Min(sixSigma.CpkU, sixSigma.CpkL);
        }
    }
}
